package org.libermundi.theorcs.core.dao;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import javax.persistence.EntityNotFoundException;

import org.libermundi.theorcs.core.model.base.Activable;
import org.libermundi.theorcs.core.model.base.Defaultable;
import org.libermundi.theorcs.core.model.base.Identifiable;
import org.libermundi.theorcs.core.model.base.Inheritable;
import org.libermundi.theorcs.core.model.base.Undeletable;
import org.libermundi.theorcs.core.util.ClazzUtils;

public abstract class AbsctractGenericDao<T extends Identifiable<I>, I extends Serializable> implements GenericDao<T, I> {
	protected Class<T> _clazz;
	protected Class<?> _mappedClazz;
	protected boolean _defaultable;
	protected boolean _activable;
	protected boolean _deletable;
	protected boolean _inheritable;
	
	/*
	 * (non-Javadoc)
	 * @see org.libermundi.theorcs.core.dao.GenericDao#load(java.io.Serializable)
	 */
    @Override
    public final T load(I id) throws EntityNotFoundException {
        T entity = get(id);
        if (entity == null) {
            throw new EntityNotFoundException("Entity " + getEntityClass() + " #" + id + " was not found");
        }
        return entity;
    }
    
    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#getAll()
     */
    @Override
    public final List<T> getAll() {
        return getAll(true);
    }
    
    public Class<T> getClazz() {
    	return _clazz;
    }
    
    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#delete(java.io.Serializable)
     */
    @Override
    public final void delete(final I id) throws UnsupportedOperationException {
        delete(load(id));
    }

    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#delete(I[])
     */
    @SuppressWarnings("unchecked")
    @Override
    public final void delete(final I... ids) throws UnsupportedOperationException {
        deleteAll(get(ids), true);
    }
    
	/*
	 * (non-Javadoc)
	 * @see org.libermundi.theorcs.core.dao.GenericDao#delete(org.libermundi.theorcs.core.model.base.Identifiable)
	 */
    @Override
    public final void delete(final T object) throws UnsupportedOperationException {
        delete(object, true);
    }
    
    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#delete(T[])
     */
    @SuppressWarnings("unchecked")
    @Override
    public final void delete(final T... objects) throws UnsupportedOperationException {
        deleteAll(Arrays.asList(objects), true);
    }

    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#deleteAll()
     */
    @Override
    public final void deleteAll() throws UnsupportedOperationException {
        deleteAll(getAll(), false);
    }

    protected void deleteAll(final Collection<T> objects, boolean checkIdDefault) throws UnsupportedOperationException {
        for (T object : objects) {
            delete(object, checkIdDefault);
        }
    }
    
    @SuppressWarnings("unchecked")
	protected void checkIfDefault(T entity) {
        if (((Defaultable<T>) entity).isDefault()) {
            throw new UnsupportedOperationException("Can't delete default entity " + getEntityClass() + " #" + entity.getId());
        }
    }
    
    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#getEntityClass()
     */
    @Override
	public Class<T> getEntityClass() {
		return _clazz;
	}    
    
    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#getMappedClass()
     */
    @Override
	public Class<?> getMappedClass() {
		return _mappedClazz;
	}    
    
    protected void checkGenericClass() {
        _defaultable = ClazzUtils.isImplementInterface(Defaultable.class, _clazz);
        _activable = ClazzUtils.isImplementInterface(Activable.class, _clazz);
        _deletable = ClazzUtils.isImplementInterface(Undeletable.class, _clazz);
        _inheritable = ClazzUtils.isImplementInterface(Inheritable.class, _clazz);
    }

    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#isActivable()
     */
    @Override
    public final boolean isActivable() {
        return _activable;
    }

    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#isDefaultable()
     */
    @Override
    public final boolean isDefaultable() {
        return _defaultable;
    }

    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#isUndeletable()
     */
    @Override
    public final boolean isUndeletable() {
        return _deletable;
    }

    /*
     * (non-Javadoc)
     * @see org.libermundi.theorcs.core.dao.GenericDao#isInheritable()
     */
    @Override
    public final boolean isInheritable() {
        return _inheritable;
    }    
    
}
